package com.aquarium.ui;

import java.util.ArrayList;
import java.util.Observable;
import java.util.Observer;

import android.app.Activity;
import android.app.ActivityManager;
import android.app.ActivityManager.RunningServiceInfo;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.bluetooth.BluetoothDevice;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.drawable.AnimationDrawable;
import android.os.Bundle;
import android.os.Handler;
import android.os.SystemClock;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

import com.aquarium.R;
import com.aquarium.bt.BTManager;
import com.aquarium.bt.BTManager.Status;
import com.aquarium.bt.DataInterpreter;
import com.aquarium.bt.DataStruct;
import com.aquarium.config.BTCommand;
import com.aquarium.module.ModuleControlService;
import com.aquarium.security.SecurityManager;
import com.sun.mail.imap.protocol.MessageSet;

public class WelcomeActivity extends Activity implements
		BTManager.StatusChangedListener, BTManager.RemoteDeviceListener,
		Observer {

	private static final String TAG = "WelcomeActivity";

	private static final int MESSAGE_SHOW_REMOTE_DEVICES = 0x10;
	private static final int MESSAGE_DISCOVERY_FINISHED = 0x11;
	private static final int MESSAGE_REQUEST_AUTHENTICATION = 0x12;
	private static final int MESSAGE_START_DISCOVERING = 0x13;
	private static final int MESSAGE_START_CONNECTING = 0x14;
	private static final int MESSAGE_RECEIVE_DATA_TIMEOUT = 0x15;
	private static final int MESSAGE_AUTHENTICATION_SUCCESS = 0x16;
	private static final int MESSAGE_AUTHENTICATION_FAIL = 0x17;
	private static final int MESSAGE_CONNECT_FAIL = 0x18;
	private static final int MESSAGE_AUTHENTICATION_IN_PROGRESS = 0x19;

	/**
	 * timeout value of waiting for controller's reply (ms)
	 */
	private static final int TIMEOUT_VALUE = 5000;

	private Context mContext;
	private BTManager mBtManager;
	private ArrayAdapter<String> mArrayAdapter;
	private ArrayList<BluetoothDevice> mDeviceList;
	private ArrayList<String> mData = new ArrayList<String>();

	private SecurityManager mSecurityManager;

	/**
	 * ListView to show scanned devices.
	 */
	private ListView mListView;

	/**
	 * the root view (layout) of scanning.
	 */
	private View mDeviceView;

	/**
	 * the TextView to show welcome message and current status.
	 */
	private TextView mStatusTextView;

	/**
	 * button to show current scanning status and start discovery again when
	 * clicked.
	 */
	private ImageView mRefreshButton;

	private int mCurrentStatus;

	/**
	 * the dialog to input password.
	 */
	private Dialog mAuthPromptDialog;

	/**
	 * the dialog to block user when authentication is in progress.
	 */
	private ProgressDialog mAuthProgressDialog;

	/**
	 * the password user input.
	 */
	private String mPassword;

	/**
	 * true means user check to remember password.
	 */
	private boolean bRememberPassword = false;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		if (isMyServiceRunning()) {
			Log.d(TAG, "service is running...");
			Intent intent = new Intent();
			intent.setClass(WelcomeActivity.this,
					SensorValueDisplayActivity.class);
			startActivity(intent);
			finish();
			return;
		}

		setContentView(R.layout.welcome_main);

		mContext = WelcomeActivity.this;
		mDeviceView = findViewById(R.id.remote_device_layout);
		mListView = (ListView) findViewById(R.id.device_list);
		mStatusTextView = (TextView) findViewById(R.id.status_text);
		mRefreshButton = (ImageView) findViewById(R.id.scanning_image);

		mDeviceList = new ArrayList<BluetoothDevice>();
		mArrayAdapter = new ArrayAdapter<String>(this, R.layout.device_entry,
				mData);

		mListView.setAdapter(mArrayAdapter);
		mListView.setOnItemClickListener(new OnItemClickListener() {

			@Override
			public void onItemClick(AdapterView<?> parent, View view,
					int position, long id) {
				Log.d(TAG,
						"clicked a item, atempt to connect a remote device now");
				mRefreshButton.setBackgroundResource(R.drawable.refresh_icon);
				mBtManager.connect(mDeviceList.get(position));
			}
		});
		mRefreshButton.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				if (mCurrentStatus == Status.DISCOVERYING) {
					Toast.makeText(WelcomeActivity.this,
							getText(R.string.scanning), Toast.LENGTH_SHORT)
							.show();
				} else {
					startDiscovery();
				}

			}
		});

		mBtManager = BTManager.getInstance();
		mBtManager.init(mContext);
		mBtManager.addObserver(this);
		mBtManager.setStatusChangedListener(this);

		mSecurityManager = SecurityManager.getInstance(mContext);

		if (mBtManager.isOpen()) {
			mHandler.sendEmptyMessageDelayed(MESSAGE_SHOW_REMOTE_DEVICES, 1000);
			mBtManager.setRemoteDeviceListener(this);
			startDiscovery();
		} else {
			mBtManager.open();
		}

		Intent intent = new Intent();
		intent.setClass(this, AlarmService.class);
		startService(intent);

		Intent moduleControlIntent = new Intent();
		moduleControlIntent.setClass(this, ModuleControlService.class);
		startService(moduleControlIntent);
	}

	private Handler mHandler = new Handler() {
		public void handleMessage(android.os.Message msg) {
			Log.d(TAG, "mHandler receive message:" + msg.what);
			switch (msg.what) {
			case MESSAGE_SHOW_REMOTE_DEVICES:
				mDeviceView.setVisibility(View.VISIBLE);
				mStatusTextView.setVisibility(View.INVISIBLE);
				break;
			case MESSAGE_DISCOVERY_FINISHED:
				showToast(getString(R.string.discovery_finish));
				mRefreshButton.setBackgroundResource(R.drawable.refresh_icon);
				// if (mDeviceList.size() == 0) {
				// mStatusTextView.setVisibility(View.VISIBLE);
				// mStatusTextView.setText("no device found");
				// }

				break;
			case MESSAGE_REQUEST_AUTHENTICATION:
				requestAuthentication();
				break;
			case MESSAGE_START_DISCOVERING:
				showToast(getString(R.string.start_discovery));
				break;
			case MESSAGE_START_CONNECTING:
				showToast(getString(R.string.connectting));
				break;
			case MESSAGE_RECEIVE_DATA_TIMEOUT:
				mAuthProgressDialog.dismiss();
				showToast(getString(R.string.receive_data_timeout));
				break;
			case MESSAGE_AUTHENTICATION_SUCCESS:
				mAuthProgressDialog.dismiss();
				// save password
				if (bRememberPassword) {
					mSecurityManager.setNeedStorePassword(true);
					mSecurityManager.storePassword(mPassword);
				}
				Intent intent = new Intent();
				intent.setClass(WelcomeActivity.this,
						SensorValueDisplayActivity.class);
				startActivity(intent);
				finish();
				break;
			case MESSAGE_AUTHENTICATION_FAIL:
				showToast(getString(R.string.authentication_fail));
				// remove password when authentication fail.
				mSecurityManager.setNeedStorePassword(false);
				mAuthProgressDialog.dismiss();
				// requestAuthentication();
				showAuthFailDialog(getString(R.string.authentication_fail));
				break;
			case MESSAGE_CONNECT_FAIL:
				showToast(getString(R.string.connect_controller_fail));
				break;
			case MESSAGE_AUTHENTICATION_IN_PROGRESS:
				showAuthProgressDialog();
				break;
			default:
				break;
			}
		};
	};

	@Override
	public void onChanged(int status) {
		Log.d(TAG, "get bt status:" + status);
		mCurrentStatus = status;
		if (status == Status.OFF) {
			// user closes bt.

		} else if (status == Status.TURNING_ON) {

		} else if (status == Status.ON) {
			mHandler.sendEmptyMessageDelayed(MESSAGE_SHOW_REMOTE_DEVICES, 1000);
			mBtManager.setRemoteDeviceListener(this);
			startDiscovery();
		} else if (status == Status.DISCOVERYING) {
			mHandler.sendEmptyMessage(MESSAGE_START_DISCOVERING);
		} else if (status == Status.DISCOVERYING_FINISHED) {
			mHandler.sendEmptyMessage(MESSAGE_DISCOVERY_FINISHED);
		} else if (status == Status.CONNECTING) {
			mHandler.sendEmptyMessage(MESSAGE_START_CONNECTING);
		} else if (status == Status.CONNECTED) {
			mHandler.sendEmptyMessage(MESSAGE_REQUEST_AUTHENTICATION);
		} else if (status == Status.CONNECT_FAILED) {
			mHandler.sendEmptyMessage(MESSAGE_CONNECT_FAIL);
		}
	}

	private void startDiscovery() {
		mData.clear();
		mDeviceList.clear();
		mArrayAdapter.notifyDataSetChanged();
		mBtManager.startDiscovery();
		mRefreshButton.setBackgroundResource(R.drawable.refresh_animation);
		((AnimationDrawable) mRefreshButton.getBackground()).start();
	}

	@Override
	public void onDeviceFound(BluetoothDevice device) {
		Log.d(TAG, "device found...");
		mDeviceList.add(device);
		mData.add(device.getName() + "\t" + device.getAddress());
		mArrayAdapter.notifyDataSetChanged();

	}

	@Override
	public void onBondStateChanged(BluetoothDevice device) {

	}

	/**
	 * show a dialog to request a password to access to the controller.
	 */
	private void requestAuthentication() {

		if (mSecurityManager.isStoredPassword()) {
			sendVarifyData(mSecurityManager.getPassword());
			return;
		}
		AlertDialog.Builder builder = new AlertDialog.Builder(this);
		LayoutInflater inflater = this.getLayoutInflater();
		final View authenticationView = inflater.inflate(
				R.layout.dialog_authentication, null);

		builder.setView(authenticationView)
				.setTitle(R.string.password_prompt)
				.setPositiveButton(R.string.ok,
						new DialogInterface.OnClickListener() {
							@Override
							public void onClick(DialogInterface dialog, int id) {
								mPassword = ((EditText) authenticationView
										.findViewById(R.id.password)).getText()
										.toString();
								bRememberPassword = ((CheckBox) authenticationView
										.findViewById(R.id.remenber_password))
										.isChecked();
								sendVarifyData(mPassword);
								dialog.dismiss();
							}
						})
				.setNegativeButton(R.string.cancel,
						new DialogInterface.OnClickListener() {
							public void onClick(DialogInterface dialog, int id) {
								dialog.cancel();
							}
						});
		mAuthPromptDialog = builder.create();
		mAuthPromptDialog.show();
	}

	private void sendVarifyData(String password) {
		final byte[] passwordBytes = BTCommand.getVarifyPasswdCommand(password);
		if (passwordBytes == null) {
			showAuthFailDialog(getString(R.string.password_length_error));
			// showToast(getString(R.string.password_length_error));
			return;
		}

		mBtManager.sendData(DataInterpreter.unpack(passwordBytes));
		mHandler.sendEmptyMessageDelayed(MESSAGE_RECEIVE_DATA_TIMEOUT,
				TIMEOUT_VALUE);
		mHandler.sendEmptyMessage(MESSAGE_AUTHENTICATION_IN_PROGRESS);

		// test code
		SystemClock.sleep(1000);
		if ("0000".equals(password)) {
			mBtManager.sendPasswdVarifyOk();
		} else {
			mBtManager.sendPasswdVarifyFail();
		}
	}

	@Override
	public void update(Observable observable, Object data) {
		if (observable instanceof BTManager) {
			final DataStruct receivedData = (DataStruct) data;
			byte[] resposeData = DataInterpreter.pack(receivedData);
			Log.d(TAG, "get responce, length:" + resposeData.length);

			for (int i = 0; i < receivedData.length; i++) {
				Log.d(TAG, "data:" + Integer.toHexString(resposeData[i] & 0xFF));
			}
			if (receivedData.prefix == 0x5a && receivedData.id == 0x01
					&& receivedData.code == 0x61 && receivedData.length == 0x01) {
				Log.d(TAG, "get responce data of authentication");
				mHandler.removeMessages(MESSAGE_RECEIVE_DATA_TIMEOUT);
				if (receivedData.data[0] == 0x00) {
					// authentication success
					mHandler.sendEmptyMessage(MESSAGE_AUTHENTICATION_SUCCESS);
				} else if (receivedData.data[0] == 0x01) {
					// authentication fail, request again
					mHandler.sendEmptyMessage(MESSAGE_AUTHENTICATION_FAIL);
				}
			}
		}

	}

	private void showAuthProgressDialog() {
		mAuthProgressDialog = new ProgressDialog(mContext);
		// mAuthProgressDialog = ProgressDialog.show(mContext, null,
		// getText(R.string.waiting_for_verification));
		mAuthProgressDialog
				.setMessage(getText(R.string.waiting_for_verification));
		mAuthProgressDialog.show();
	}

	private void showAuthFailDialog(String message) {
		AlertDialog.Builder builder = new AlertDialog.Builder(this);
		LayoutInflater inflater = this.getLayoutInflater();
		final View authFailView = inflater.inflate(
				R.layout.dialog_authentication_fail, null);
		((TextView) authFailView.findViewById(R.id.auth_fail_message))
				.setText(message);

		builder.setView(authFailView)
				.setTitle(getText(R.string.error))
				.setPositiveButton(R.string.retry,
						new DialogInterface.OnClickListener() {
							@Override
							public void onClick(DialogInterface dialog, int id) {
								requestAuthentication();
								dialog.dismiss();
							}
						})
				.setNegativeButton(R.string.leave,
						new DialogInterface.OnClickListener() {
							public void onClick(DialogInterface dialog, int id) {
								dialog.cancel();
							}
						}).create().show();
	}

	private void showToast(String content) {
		Toast.makeText(mContext, content, Toast.LENGTH_SHORT).show();
	}

	@Override
	protected void onStop() {
		super.onStop();
		mBtManager.deleteObserver(this);
	}

	private boolean isMyServiceRunning() {
		ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
		for (RunningServiceInfo service : manager
				.getRunningServices(Integer.MAX_VALUE)) {
			if (AlarmService.class.getName().equals(
					service.service.getClassName())
					|| ModuleControlService.class.getName().equals(
							service.service.getClassName())) {
				return true;
			}
		}
		return false;
	}
}
